package org.litespring.context.support;

import org.litespring.aop.aspectj.AspectJAutoProxyCreator;
import org.litespring.beans.factory.NoSuchBeanDefinitionException;
import org.litespring.beans.factory.annotation.AutowiredAnnotationProcessor;
import org.litespring.beans.factory.config.ConfigurableBeanFactory;
import org.litespring.beans.factory.support.DefaultBeanFactory;
import org.litespring.beans.factory.xml.XmlBeanDefinitionReader;
import org.litespring.context.ApplicationContext;
import org.litespring.core.io.Resource;
import org.litespring.util.ClassUtils;

import java.util.List;

/**
 * @author ChangLiang
 * @date 2020/7/22
 */
public abstract class AbstractApplicationContext implements ApplicationContext {

    private DefaultBeanFactory factory;

    private ClassLoader beanClassLoader;

    public AbstractApplicationContext(String configFile) {
        factory = new DefaultBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        Resource resource = this.getResourceByPath(configFile);
        reader.loadBeanDefinitions(resource);

        // 通过ApplicationContext set ClassLoader后，其持有的factory也具备这个能力
        factory.setBeanClassLoader(this.beanClassLoader);

        registerBeanPostProcessors(factory);
    }

    @Override
    public Object getBean(String beanId) {
        return factory.getBean(beanId);
    }

    protected abstract Resource getResourceByPath(String path);

    public void setBeanClassLoader(ClassLoader beanClassLoader) {
        this.beanClassLoader = beanClassLoader;
    }

    public ClassLoader getBeanClassLoader() {
        return this.beanClassLoader != null ? beanClassLoader : ClassUtils.getDefaultClassLoader();
    }

    protected void registerBeanPostProcessors(ConfigurableBeanFactory beanFactory) {
        {
            AutowiredAnnotationProcessor processor = new AutowiredAnnotationProcessor();
            processor.setBeanFactory(beanFactory);
            beanFactory.addBeanPostProcessor(processor);
        }
        {
            AspectJAutoProxyCreator processor = new AspectJAutoProxyCreator();
            processor.setBeanFactory(beanFactory);
            beanFactory.addBeanPostProcessor(processor);
        }
    }

    @Override
    public Class<?> getType(String beanId) throws NoSuchBeanDefinitionException {
        return factory.getType(beanId);
    }

    @Override
    public List<Object> getBeansByType(Class<?> type) {
        return factory.getBeansByType(type);
    }
}
